package munci.old.learn;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import munci.old.java.Type;
import munci.old.know.Env;
import munci.old.know.Stack;
import munci.old.know.words.MethodWord;
import munci.old.know.words.Word;
import munci.old.use.Tokens;


public class Members {
	
	public static final Word[] WORDS =
		MethodWord.all(new Word.Book(Members.class)).toArray();
	
	@MethodWord.Name("!")
	public static void invoke(Object obj, Stack stack, CharSequence name)
			throws NoSuchMethodException {
		invoke(Env.get().stack, obj.getClass(), obj, stack, name.toString());
	}

	@MethodWord.Name("!") 
	public static void invoke(final Stack stack, final Type type, final CharSequence name)
			throws NoSuchMethodException, ClassNotFoundException {
		Env env = Env.get();
		invoke(env.stack, type.toClass(env.dict), null, stack, name.toString());
	}

	private static void invoke(Stack stack, Class<?> type, Object obj, Stack args, String name)
	throws NoSuchMethodException {
		for (Method m : type.getMethods()) {
			if (m.getName().equals(name) && stack.invoke(m, obj, args)) return;
		}
		throw new NoSuchMethodException(name);
	}
	
	@MethodWord.Compile("!") public static Tokens invoke(
			Tokens obj, List<Object> args, CharSequence name) {
		Tokens toks = new Tokens().addAll(obj).add(".").add(name.toString()).add("(");
		int index = 0;
		for (Object arg : args) {
			if (index++ == 0) toks.add(",");
			toks.addAll((Tokens) arg);
		}
		return toks.add(")");
	}
	
	@MethodWord.Compile("!")
	public static Tokens invoke(Stack args, Tokens type, CharSequence name) {
		Tokens toks = new Tokens().addAll(type).add(".").add(name.toString()).add("(");
		int index = 0;
		for (Object arg : args.values()) {
			if (index++ == 0) toks.add(",");
			toks.addAll((Tokens) arg);
		}
		return toks.add(")");
	}
	
	@MethodWord.Name("?") 
	public static void get(Object obj, CharSequence name) throws Exception {
		Field f = obj.getClass().getField(name.toString());
		Env.get().stack.push(f.get(obj), f.getType());
	}
	
	@MethodWord.Name("?") 
	public static void get_(Type type, CharSequence name) throws Exception {
		Env env = Env.get();
		Field f = type.toClass(env.dict).getField(name.toString());
		env.stack.push(f.get(null), f.getType());
	}
	
	@MethodWord.Compile("?") public static Tokens get(Tokens referent, CharSequence name) {
		return new Tokens().addAll(referent).add(".").add(name.toString());
	}
}
